interface Options {
  el: string | HTMLElement,
}

interface VueCls {
  options: Options,

  init(): void
}

interface VNode {
  tag: string,
  text?: string,
  children?: VNode[]
}

class Dom {
  private createElement(tag: string) {
    return document.createElement(tag)
  }

  private setText(el: HTMLElement, text: string | null) {
    el.textContent = text
  }

  protected render(data: VNode) {
    let root = this.createElement(data.tag)
    if (data.children && Array.isArray(data.children)) {
      data.children.forEach(item => {
        let child = this.render(item)
        root.appendChild(child)
      })
    } else {
      this.setText(root, data.text)
    }

    return root
  }
}

class Vue extends Dom implements VueCls {
  options: Options

  constructor(options) {
    super()
    this.options = options
    this.init()
  }

  static version() {
    return '1.0.0'
  }

  init(): void {
    let data: VNode = {
      tag: 'div',
      text: '我是div',
      children: [
        {
          tag: 'section',
          text: '我是section1'
        },
        {
          tag: 'section',
          text: '我是section2',
        }
      ]
    }
    let app = typeof this.options.el === 'string' ? document.querySelector(this.options.el) : this.options.el
    app.appendChild(this.render(data))
  }
}

new Vue({
  el: '#app'
})